/**
Metamorfose is an interactive ecosystem, which uses computer vision
and sound analysis to define its basic rules.
Copyright (C) 2008  laboratorio (info@laboratorio.us)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

class Parasite {
  Vector3D loc;
  Vector3D vel;
  Vector3D acc;
  float mass;
  float max_vel;
  float G;

  /**
   * Class constructor
   *
   * @param a acceleration vector
   * @param v velocity vector
   * @param l location vector
   * @param m_ mass constant
   */
  Parasite(Vector3D a, Vector3D v, Vector3D l, float m_) {
    acc = a.copy();
    vel = v.copy();
    loc = l.copy();
    mass = m_;
    max_vel = random(1.0, 1.6);
    G = 0.4f;
  }
  
  /**
   * Gets the location vector
   */  
  Vector3D getLoc() {
    return loc;
  }

  /**
   * Gets the velocity vector
   */
  Vector3D getVel() {
    return vel;
  }
  
  /**
   * Gets the mass constant
   */  
  float getMass() {
    return mass;
  }
  
  /**
   * Calculates the gravitational force against another parasite.
   * Based on Daniel Shiffman's code (http://www.shiffman.net/teaching/nature/forces/)
   *
   * @param t another parasite
   * @return the direction vector
   */  
  Vector3D calcGravForce(Parasite t) {
    Vector3D dir = Vector3D.sub(t.getLoc(), loc);
    float d = dir.magnitude();
    d = constrain(d, 180.0, 210.0f);
    dir.normalize();
    float force = ((G * mass * t.getMass()) / sq(d));
    dir.mult(force);     
    return dir;
  }
  
  /**
   * Adds a given force to the current object
   */
  void add_force(Vector3D force) {
    force.div(mass);
    acc.add(force);
  }

  /**
   * Moves and displays the object
   */
  void go() {
    update();
    render();
  }
  
  /**
   * Updates object's attributes
   */  
  void update() {
    vel.add(acc);
    vel.limit(max_vel);
    loc.add(vel);
    acc.setXYZ(0.0,0.0,0.0);
    borders();
  }
  
  /**
   * Displays the object
   */  
  void render() {
    ellipseMode(CENTER);
    noStroke();
    fill(0, 0, 0, 98);
    ellipse(loc.x, loc.y, ((mass * 2) + random(1)), ((mass * 2) + random(1)));
  }

  /**
   * Workaround edges
   */
  void borders() {
    float r = 2.0f;
    if (loc.x < -r) loc.x = width+r;
    if (loc.y < -r) loc.y = height+r;
    if (loc.x > width+r) loc.x = -r;
    if (loc.y > height+r) loc.y = -r;
  }  
}